﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Joy.Erp.BasicArchives.Asns;
using Joy.Erp.BasicArchives.Core;
using Joy.Erp.BasicArchives.ItemMasters;
using Joy.Erp.BasicArchives.Procurements;
using Joy.Erp.BasicArchives.Production;
using Joy.Erp.BasicArchives.Receipt;
using Joy.Erp.Ufida.ItemMasters;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;

namespace Joy.Erp.Ufida.Pmc
{
    [Authorize]
    public class ProductionPlatformAppService : UfidaAppService, IProductionPlatformAppService
    {
        /// <summary>
        /// 成套基数
        /// </summary>
        const decimal BaseNumber = 1;
        protected IProductionOrderRepository ProductionOrderRepository =>
            LazyServiceProvider.LazyGetRequiredService<IProductionOrderRepository>();

        protected IBomMasterAppService BomMasterAppService =>
            LazyServiceProvider.LazyGetRequiredService<IBomMasterAppService>();

        protected ICurrentStockUfidaAppService CurrentStockUfidaAppService =>
            LazyServiceProvider.LazyGetRequiredService<ICurrentStockUfidaAppService>();

        protected IReceivementRepository ReceivementRepository =>
            LazyServiceProvider.LazyGetRequiredService<IReceivementRepository>();

        protected IAsnRepository AsnRepository =>
            LazyServiceProvider.LazyGetRequiredService<IAsnRepository>();

        protected IPurchaseOrderRepository PurchaseOrderRepository =>
            LazyServiceProvider.LazyGetRequiredService<IPurchaseOrderRepository>();

        protected IPurchaseRequisitionRepository PurchaseRequisitionRepository =>
            LazyServiceProvider.LazyGetRequiredService<IPurchaseRequisitionRepository>();

        protected IDemandOrderCacheService DemandOrderCacheService =>
            LazyServiceProvider.LazyGetRequiredService<IDemandOrderCacheService>();

        public async Task<PagedResultDto<DemandOrderDto>> GetListAsync(
            GetDemandOrderPagedInput input
        )
        {
            // 检查缓存是否存在或是否强制刷新
            if (input.ForceRefresh || !await DemandOrderCacheService.ExistsAsync())
            {
                // 加载全部数据
                var allDemandOrders = await LoadAllDemandOrdersAsync();

                // 存入缓存
                await DemandOrderCacheService.SetCacheAsync(allDemandOrders);
            }

            // 从缓存获取所有数据
            var allData = await DemandOrderCacheService.GetAllAsync();

            // 应用齐套状态筛选
            if (input.ExcludedKitStatuses != null && input.ExcludedKitStatuses.Any())
            {
                allData = allData
                    .Where(x => !input.ExcludedKitStatuses.Contains(x.KitStatus))
                    .ToList();
            }

            // 手动分页
            var totalCount = allData.Count;
            var pagedList = allData.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            return new PagedResultDto<DemandOrderDto>(totalCount, pagedList);
        }

        /// <summary>
        /// 加载全部需求订单数据（树状结构）
        /// </summary>
        private async Task<List<DemandOrderDto>> LoadAllDemandOrdersAsync()
        {
            var list = new List<DemandOrderDto>();

            // 1. 从数据库中读取所有生产订单
            var porders = await ProductionOrderRepository.GetListAsync(
                x =>
                    x.IsDeleted == false
                    && (
                        x.ProductionStatus == ProductionStatus.Created
                        || x.ProductionStatus == ProductionStatus.Started
                    )
                    && !(
                        string.IsNullOrWhiteSpace(x.DemandCode)
                        && string.IsNullOrWhiteSpace(x.Seiban)
                    )
                    && x.OrderType.DisplayName != "返工生产订单-包装计划",
                true
            );

            // 2. 从读取的数据中找到所有生产料品名称以"减震器"结尾的生产订单作为根节点生产订单
            var rootOrders = porders.Where(x => x.ItemName != null && x.ItemName.EndsWith("减震器")).ToList();

            // 3. 循环所有根节点生产订单，用递归方法构建树状结构
            foreach (var porder in rootOrders)
            {
                var visitedOrderIds = new HashSet<Guid>();
                var demandOrderDto = BuildDemandOrderRecursive(porders, porder, visitedOrderIds);
                list.Add(demandOrderDto);
            }

            //TODO:订单优先级的逻辑
            return list.OrderBy(x => x.ProductionStatus)
                .ThenBy(x => x.StartDate.Date)
                .ThenBy(x => x.TradeType)
                .ToList();
        }

        /// <summary>
        /// 递归构建需求订单树状结构
        /// </summary>
        /// <param name="allPorders">所有生产订单列表，用于查找半成品订单</param>
        /// <param name="currentPorder">当前处理的生产订单，用于获取当前节点和子项备料</param>
        /// <param name="visitedOrderIds">已访问的订单ID集合，用于防止循环引用导致的死循环</param>
        private DemandOrderDto BuildDemandOrderRecursive(
            List<ProductionOrder> allPorders,
            ProductionOrder currentPorder,
            HashSet<Guid> visitedOrderIds)
        {
            // 1. 创建当前节点的 DemandOrderDto
            var demandOrderDto = new DemandOrderDto();
            
            // 2. 使用当前订单的信息
            demandOrderDto.DocNo = currentPorder.Code;
            demandOrderDto.DocType = currentPorder.OrderType.DisplayName;
            demandOrderDto.ProductionStatus = currentPorder.ProductionStatus;
            demandOrderDto.TradeType = string.IsNullOrWhiteSpace(currentPorder.Seiban) ? 0 : 1;
            demandOrderDto.Seiban = currentPorder.Seiban;
            demandOrderDto.DemandCode = currentPorder.DemandCode;
            demandOrderDto.ProductItemMasterId = currentPorder.ItemMasterId;
            demandOrderDto.ProductItemCode = currentPorder.ItemCode;
            demandOrderDto.ProductItemName = currentPorder.ItemName;
            demandOrderDto.ProductItemSpec = currentPorder.ItemSpec;
            demandOrderDto.ProductQuantity = currentPorder.Quantity;
            demandOrderDto.ComplatedQuantity = currentPorder.ComplatedQuantity;
            demandOrderDto.StartDate = currentPorder.StartDate;
            demandOrderDto.AdjustedStartDate = currentPorder.StartDate;
            demandOrderDto.ItemMasterId = currentPorder.ItemMasterId;
            demandOrderDto.ItemCode = currentPorder.ItemCode;
            demandOrderDto.ItemName = currentPorder.ItemName;
            demandOrderDto.ItemSpec = currentPorder.ItemSpec;
            demandOrderDto.Quantity = currentPorder.Quantity;
            
            // 3. 初始化子项列表
            demandOrderDto.Children = new List<DemandOrderDto>();

            // 4. 检查循环引用：如果当前订单已经在递归路径中被访问过，说明存在循环引用，直接返回（避免死循环）
            if (visitedOrderIds.Contains(currentPorder.Id))
            {
                // 存在循环引用，返回当前节点但不继续递归处理子项
                return demandOrderDto;
            }

            // 5. 将当前订单ID添加到已访问集合
            visitedOrderIds.Add(currentPorder.Id);

            // 6. 如果当前订单没有子项（备料），直接返回
            if (currentPorder.Children == null || currentPorder.Children.Count == 0)
            {
                // 递归返回前移除当前订单ID（允许在其他路径中再次访问）
                visitedOrderIds.Remove(currentPorder.Id);
                return demandOrderDto;
            }

            // 7. 循环生产订单备料
            foreach (var pop in currentPorder.Children)
            {
                var childDemandOrderDto = new DemandOrderDto();
                // 使用父节点（当前订单）的信息
                childDemandOrderDto.DocNo = currentPorder.Code;
                childDemandOrderDto.DocType = currentPorder.OrderType.DisplayName;
                childDemandOrderDto.ProductionStatus = currentPorder.ProductionStatus;
                childDemandOrderDto.TradeType = string.IsNullOrWhiteSpace(currentPorder.Seiban) ? 0 : 1;
                childDemandOrderDto.Seiban = currentPorder.Seiban;
                childDemandOrderDto.DemandCode = currentPorder.DemandCode;
                childDemandOrderDto.ProductItemMasterId = currentPorder.ItemMasterId;
                childDemandOrderDto.ProductItemCode = currentPorder.ItemCode;
                childDemandOrderDto.ProductItemName = currentPorder.ItemName;
                childDemandOrderDto.ProductItemSpec = currentPorder.ItemSpec;
                childDemandOrderDto.ProductQuantity = currentPorder.Quantity;
                childDemandOrderDto.ComplatedQuantity = currentPorder.ComplatedQuantity;
                childDemandOrderDto.StartDate = currentPorder.StartDate;
                childDemandOrderDto.AdjustedStartDate = currentPorder.StartDate;
                // 使用备料的料品信息
                childDemandOrderDto.ItemMasterId = pop.ItemMasterId;
                childDemandOrderDto.ItemCode = pop.ItemCode;
                childDemandOrderDto.ItemName = pop.ItemName;
                childDemandOrderDto.ItemSpec = pop.ItemSpec;
                childDemandOrderDto.Quantity = pop.Quantity;
                childDemandOrderDto.AdjustedQuantity = pop.Quantity;
                childDemandOrderDto.IssuedQuantity = pop.IssuedQuantity;

                // 6. 判断是采购件还是半成品
                if (pop.ItemMaster.ItemFormAttribute == 9)
                {
                    // 6.1 如果是采购件，直接创建 DemandOrderDto 对象并根据生产订单备料数据赋值
                    childDemandOrderDto.Children = new List<DemandOrderDto>();
                }
                else
                {
                    // 6.2 如果不是采购件则当做半成品
                    // 6.2.1 从第一次读取的所有生产订单中找到与当前生产订单的需求类型和番号同时相同
                    // 并且生产数量与备料的需求数量也相同的生产订单作为半成品的生产订单
                    var semiProductOrder = allPorders.FirstOrDefault(
                        x => x.ItemMasterId == pop.ItemMasterId
                        && x.DemandCode == currentPorder.DemandCode
                        && x.Seiban == currentPorder.Seiban
                        && x.Quantity == pop.Quantity);

                    if (semiProductOrder != null)
                    {
                        // 6.2.2 如果匹配到了生产订单，递归调用自己构建半成品的子树
                        // 注意：传递同一个 visitedOrderIds 集合以检测循环引用
                        var semiProductDemandOrder = BuildDemandOrderRecursive(
                            allPorders,
                            semiProductOrder,
                            visitedOrderIds);
                        
                        // 将半成品的子项赋值给当前备料项
                        childDemandOrderDto.Children = semiProductDemandOrder.Children;
                    }
                    else
                    {
                        // 如果匹配不到半成品订单，children就为无数据的list
                        childDemandOrderDto.Children = new List<DemandOrderDto>();
                    }
                }

                demandOrderDto.Children.Add(childDemandOrderDto);
            }

            // 递归返回前移除当前订单ID（允许在其他路径中再次访问）
            visitedOrderIds.Remove(currentPorder.Id);

            return demandOrderDto;
        }

        public async Task<bool> UpdateDemandOrderAsync(UpdateDemandOrderInput input)
        {
            return await DemandOrderCacheService.UpdateAsync(
                input.DocNo,
                input.DocType,
                input.DemandOrder
            );
        }

        public async Task ClearCacheAsync()
        {
            await DemandOrderCacheService.ClearAsync();
        }

        public async Task<List<DemandOrderDto>> KitAnalysisAsync(KitInput input)
        {
            // 从缓存获取所有需求订单数据
            var demandOrders = await DemandOrderCacheService.GetAllAsync();

            if (demandOrders == null || demandOrders.Count == 0)
            {
                throw new Volo.Abp.BusinessException("请先加载需求订单数据");
            }

            var supplyCache = new Dictionary<string, List<SupplyOrderDto>>();
            var occupiedCache = new Dictionary<string, List<OccupiedRecordDto>>();

            //现存量加入supplyCache
            var currentStockLines = await CurrentStockUfidaAppService.GetAllAsync();
            foreach (var currentStockLine in currentStockLines)
            {
                var supplyOrderDto = new SupplyOrderDto();

                supplyOrderDto.DocNo = currentStockLine.ID.ToString();
                supplyOrderDto.DocType = "现存量";
                supplyOrderDto.ItemMasterId = Guid.Empty;
                supplyOrderDto.ItemCode = currentStockLine.ItemCode;
                supplyOrderDto.ItemName = currentStockLine.ItemName;
                supplyOrderDto.ItemSpec = currentStockLine.ItemSpec;
                supplyOrderDto.SupplyDate = DateTime.Now.Date;
                supplyOrderDto.Quantity = currentStockLine.Qty;

                var supplylist = supplyCache.GetValueOrDefault(supplyOrderDto.ItemCode);
                if (supplylist == null)
                {
                    supplylist = new List<SupplyOrderDto>();
                    supplyCache.Add(supplyOrderDto.ItemCode, supplylist);
                }

                supplylist.Add(supplyOrderDto);
            }

            //收货单加入supplyCache
            var receivementLines = await ReceivementRepository.GetChildrenPagedListAsync(
                x =>
                    x.Document.IsDeleted == false
                    && (
                        x.Document.DocumentStatus == DocumentStatus.Open
                        || x.Document.DocumentStatus == DocumentStatus.Waiting
                    ),
                0,
                int.MaxValue,
                null,
                true
            );
            foreach (var receivementLine in receivementLines)
            {
                var supplyOrderDto = new SupplyOrderDto();

                supplyOrderDto.DocNo = receivementLine.Document.Code;
                supplyOrderDto.DocType = "收货单";
                supplyOrderDto.ItemMasterId = receivementLine.ItemMasterId;
                supplyOrderDto.ItemCode = receivementLine.ItemCode;
                supplyOrderDto.ItemName = receivementLine.ItemName;
                supplyOrderDto.ItemSpec = receivementLine.ItemSpec;
                supplyOrderDto.SupplyDate = receivementLine.Document.BusinessDate;
                supplyOrderDto.Quantity = receivementLine.Quantity;

                var supplylist = supplyCache.GetValueOrDefault(receivementLine.ItemCode);
                if (supplylist == null)
                {
                    supplylist = new List<SupplyOrderDto>();
                    supplyCache.Add(receivementLine.ItemCode, supplylist);
                }

                supplylist.Add(supplyOrderDto);
            }

            //asn单加入supplyCache
            var asnLines = await AsnRepository.GetChildrenPagedListAsync(
                x =>
                    x.Document.IsDeleted == false
                    && x.Document.ArriveDate.HasValue
                    && x.Document.DocumentStatus != DocumentStatus.Closed,
                0,
                int.MaxValue,
                null,
                true
            );
            foreach (var asnLine in asnLines)
            {
                var supplyOrderDto = new SupplyOrderDto();

                supplyOrderDto.DocNo = asnLine.Document.Code;
                supplyOrderDto.DocType = "ASN单";
                supplyOrderDto.ItemMasterId = asnLine.ItemMasterId;
                supplyOrderDto.ItemCode = asnLine.ItemCode;
                supplyOrderDto.ItemName = asnLine.ItemName;
                supplyOrderDto.ItemSpec = asnLine.ItemSpec;
                supplyOrderDto.SupplyDate = asnLine.Document.ArriveDate.Value;
                supplyOrderDto.Quantity = asnLine.Quantity - asnLine.ReceivedQuantity;

                var supplylist = supplyCache.GetValueOrDefault(asnLine.ItemCode);
                if (supplylist == null)
                {
                    supplylist = new List<SupplyOrderDto>();
                    supplyCache.Add(asnLine.ItemCode, supplylist);
                }

                supplylist.Add(supplyOrderDto);
            }

            //采购订单加入supplyCache
            var purchaseOrderLines = await PurchaseOrderRepository.GetChildrenPagedListAsync(
                x =>
                    x.Document.IsDeleted == false
                    && x.DeliveryDate.HasValue
                    && x.Document.DocumentStatus != DocumentStatus.Closed,
                0,
                int.MaxValue,
                null,
                true
            );
            foreach (var purchaseOrderLine in purchaseOrderLines)
            {
                var supplyOrderDto = new SupplyOrderDto();

                supplyOrderDto.DocNo = purchaseOrderLine.Document.Code;
                supplyOrderDto.DocType = "采购订单";
                supplyOrderDto.ItemMasterId = purchaseOrderLine.ItemMasterId;
                supplyOrderDto.ItemCode = purchaseOrderLine.ItemCode;
                supplyOrderDto.ItemName = purchaseOrderLine.ItemName;
                supplyOrderDto.ItemSpec = purchaseOrderLine.ItemSpec;
                supplyOrderDto.SupplyDate =
                    purchaseOrderLine.NewDeliveryDate //最新交期
                    ?? purchaseOrderLine.SupplierDeliveryDate //供应商回复交期
                    ?? purchaseOrderLine.RequireDeliveryDate //要求到货日期
                    ?? purchaseOrderLine.DeliveryDate.Value; //交期
                supplyOrderDto.Quantity = purchaseOrderLine.RemainingQuantity;

                var supplylist = supplyCache.GetValueOrDefault(purchaseOrderLine.ItemCode);
                if (supplylist == null)
                {
                    supplylist = new List<SupplyOrderDto>();
                    supplyCache.Add(purchaseOrderLine.ItemCode, supplylist);
                }

                supplylist.Add(supplyOrderDto);
            }

            //请购单加入supplyCache
            var purchaseRequisitionLines =
                await PurchaseRequisitionRepository.GetChildrenPagedListAsync(
                    x =>
                        x.Document.IsDeleted == false
                        && x.DeliveryDate.HasValue
                        && x.Document.DocumentStatus != DocumentStatus.Closed,
                    0,
                    int.MaxValue,
                    null,
                    true
                );
            foreach (var purchaseRequisitionLine in purchaseRequisitionLines)
            {
                var supplyOrderDto = new SupplyOrderDto();

                supplyOrderDto.DocNo = purchaseRequisitionLine.Document.Code;
                supplyOrderDto.DocType = "请购单";
                supplyOrderDto.ItemMasterId = purchaseRequisitionLine.ItemMasterId;
                supplyOrderDto.ItemCode = purchaseRequisitionLine.ItemCode;
                supplyOrderDto.ItemName = purchaseRequisitionLine.ItemName;
                supplyOrderDto.ItemSpec = purchaseRequisitionLine.ItemSpec;
                supplyOrderDto.SupplyDate = purchaseRequisitionLine.DeliveryDate.Value;
                supplyOrderDto.Quantity = purchaseRequisitionLine.RemainingQuantity;

                var supplylist = supplyCache.GetValueOrDefault(purchaseRequisitionLine.ItemCode);
                if (supplylist == null)
                {
                    supplylist = new List<SupplyOrderDto>();
                    supplyCache.Add(purchaseRequisitionLine.ItemCode, supplylist);
                }

                supplylist.Add(supplyOrderDto);
            }

            //将需求按照业务逻辑去排序
            //TODO:订单优先级的逻辑
            var demandlist = demandOrders
                .OrderBy(x => x.ProductionStatus)
                .ThenBy(x => x.StartDate.Date)
                .ThenBy(x => x.TradeType)
                .ToList();

            //对每个需求订单进行齐套计算
            foreach (var demand in demandlist)
            {
                //计算齐套
                CalculateKitForDemand(demand, supplyCache, occupiedCache, input.AllocationType);
            }

            // 计算完成后更新缓存
            await DemandOrderCacheService.SetCacheAsync(demandOrders);

            return demandOrders;
        }

        /// <summary>
        /// 计算需求单的齐套情况
        /// </summary>
        private void CalculateKitForDemand(
            DemandOrderDto demand,
            Dictionary<string, List<SupplyOrderDto>> supplyCache,
            Dictionary<string, List<OccupiedRecordDto>> occupiedCache,
            string allocationType
        )
        {
            //没有子项的不计算齐套
            if (demand.Children == null || demand.Children.Count <= 0)
            {
                demand.KitCount = 0;
                demand.KitStatus = "无子项";
                return;
            }

            //1. 计算当前需求需要的套数
            var needKitCount = Convert.ToInt32(demand.ProductQuantity / BaseNumber);

            //2. 将树结构展平，收集所有最末级的需求项并按料号合并
            var flattenedDemands = new Dictionary<string, FlattenedDemandItemDto>();
            FlattenDemandTree(demand, needKitCount, flattenedDemands);

            //3. 计算每个料号的可分配套数（考虑领用配平）
            foreach (var item in flattenedDemands.Values)
            {
                //3.1. 根据供应列表和占用列表计算可分配数量
                var supplylist =
                    supplyCache.GetValueOrDefault(item.ItemCode) ?? new List<SupplyOrderDto>();
                var occupiedlist =
                    occupiedCache.GetValueOrDefault(item.ItemCode) ?? new List<OccupiedRecordDto>();
                var availableSupply =
                    supplylist.Sum(x => x.Quantity) - occupiedlist.Sum(x => x.OccupiedQuantity);

                //3.2. 计算可分配套数
                if (item.DemandItems.Count == 1)
                {
                    //只有一条需求时，直接计算可分配套数
                    var demandQuantity = item.DemandItems[0].Quantity;
                    item.AvailableKitCount =
                        demandQuantity > 0
                            ? Math.Min((int)(availableSupply / demandQuantity), needKitCount)
                            : 0;
                }
                else
                {
                    //多条需求时，使用配平算法计算可分配套数
                    item.AvailableKitCount = CalculateKitCountWithBalancing(
                        item.DemandItems,
                        availableSupply,
                        needKitCount
                    );
                }
            }

            //4. 根据分配方式调整每个料号的可分配套数
            if (allocationType == "满额分配")
            {
                //满额分配：不做任何调整，每个料号按自己的 AvailableKitCount 分配
            }
            else if (allocationType == "最小分配")
            {
                //最小分配：所有料号统一按最小的 AvailableKitCount 分配
                var minKitCount = flattenedDemands.Values.Min(x => x.AvailableKitCount);
                foreach (var item in flattenedDemands.Values)
                {
                    item.AvailableKitCount = minKitCount;
                }
            }
            else if (allocationType == "不分配")
            {
                //不分配：只有全部齐套才分配，否则都设为0
                var minKitCount = flattenedDemands.Values.Min(x => x.AvailableKitCount);
                var allKitCount = minKitCount >= needKitCount ? needKitCount : 0;
                foreach (var item in flattenedDemands.Values)
                {
                    item.AvailableKitCount = allKitCount;
                }
            }

            //5. 执行分配并记录占用情况
            foreach (var item in flattenedDemands.Values)
            {
                //5.1. 获取该料号要分配的套数
                var allocatedKitCount = item.AvailableKitCount;

                //如果不需要分配，跳过
                if (allocatedKitCount <= 0)
                    continue;

                //5.2. 读取供应列表和占用列表
                var supplylist =
                    supplyCache.GetValueOrDefault(item.ItemCode) ?? new List<SupplyOrderDto>();
                var occupiedlist = occupiedCache.GetValueOrDefault(item.ItemCode);
                if (occupiedlist == null)
                {
                    occupiedlist = new List<OccupiedRecordDto>();
                    occupiedCache[item.ItemCode] = occupiedlist;
                }

                //5.3. 为每个需求子项分配供应并记录占用
                foreach (var demandItem in item.DemandItems)
                {
                    //5.3.1. 计算该子项需要占用的数量
                    decimal quantityPerKit = demandItem.AdjustedQuantity / needKitCount;
                    decimal targetQuantity = quantityPerKit * allocatedKitCount;
                    decimal stillNeeded = Math.Max(0, targetQuantity - demandItem.IssuedQuantity);

                    //如果不需要占用，跳过
                    if (stillNeeded <= 0)
                        continue;

                    stillNeeded = Math.Ceiling(stillNeeded);

                    //5.3.2. 从供应列表中为该子项分配
                    var leaveNeedOccupiedQuantity = stillNeeded;
                    foreach (var supplyitem in supplylist)
                    {
                        if (leaveNeedOccupiedQuantity <= 0)
                            break;

                        //计算当前供应已被占用的数量
                        var currentSupplyOccupiedQuantity = occupiedlist
                            .Where(x =>
                                x.SupplyOrderDocNo == supplyitem.DocNo
                                && x.SupplyOrderDocType == supplyitem.DocType
                            )
                            .Sum(x => x.OccupiedQuantity);

                        //计算当前供应可分配的数量
                        var currentSupplyCanBeAllocated =
                            supplyitem.Quantity - currentSupplyOccupiedQuantity;
                        if (currentSupplyCanBeAllocated <= 0)
                            continue;

                        //创建占用记录（关联到具体的子项）
                        var occupiedQuantity = Math.Min(
                            currentSupplyCanBeAllocated,
                            leaveNeedOccupiedQuantity
                        );
                        var occupiedRecordDto = new OccupiedRecordDto
                        {
                            DemandOrderDocNo = demandItem.DocNo, //子项所属的订单号
                            DemandOrderDocType = demandItem.DocType, //子项所属的订单类型
                            SupplyOrderDocNo = supplyitem.DocNo,
                            SupplyOrderDocType = supplyitem.DocType,
                            ItemMasterId = supplyitem.ItemMasterId,
                            ItemCode = supplyitem.ItemCode,
                            ItemName = supplyitem.ItemName,
                            ItemSpec = supplyitem.ItemSpec,
                            OccupiedQuantity = occupiedQuantity,
                        };
                        occupiedlist.Add(occupiedRecordDto);

                        //将占用记录也添加到该子项中（便于后续追溯）
                        if (demandItem.OccupiedRecords == null)
                            demandItem.OccupiedRecords = new List<OccupiedRecordDto>();
                        demandItem.OccupiedRecords.Add(occupiedRecordDto);

                        //更新剩余需要分配数量
                        leaveNeedOccupiedQuantity -= occupiedQuantity;
                    }

                    //5.3.3. 设置该末级子项的齐套数量和状态
                    demandItem.KitCount = allocatedKitCount;
                    SetKitStatus(demandItem, needKitCount);
                }

                //5.4. 记录实际分配的套数
                item.AllocatedKitCount = allocatedKitCount;
            }

            //6. 为包含子项的半成品设置齐套数量和状态（自底向上）
            SetIntermediateKitStatus(demand, needKitCount);

            //7. 设置根需求的齐套情况（根据所有子项的最小齐套数）
            if (demand.Children != null && demand.Children.Count > 0)
            {
                demand.KitCount = demand.Children.Min(x => x.KitCount ?? 0);
                SetKitStatus(demand, needKitCount);
            }
        }

        /// <summary>
        /// 设置齐套状态
        /// </summary>
        private void SetKitStatus(DemandOrderDto demandOrder, int needKitCount)
        {
            var kitCount = demandOrder.KitCount ?? 0;
            if (kitCount <= 0)
            {
                demandOrder.KitStatus = "不齐套";
            }
            else if (kitCount < needKitCount)
            {
                demandOrder.KitStatus = "部分齐套";
            }
            else
            {
                demandOrder.KitStatus = "全部齐套";
            }
        }

        /// <summary>
        /// 为包含子项的半成品设置齐套数量和状态（递归处理）
        /// </summary>
        private void SetIntermediateKitStatus(DemandOrderDto demand, int needKitCount)
        {
            if (demand.Children == null || demand.Children.Count <= 0)
                return;

            //先递归处理所有子项（深度优先，从叶子节点向上）
            foreach (var child in demand.Children)
            {
                if (child.Children != null && child.Children.Count > 0)
                {
                    SetIntermediateKitStatus(child, needKitCount);
                }
            }

            //如果当前节点有子项，根据子项设置齐套信息
            if (demand.Children.Any(x => x.Children != null && x.Children.Count > 0))
            {
                //这是一个中间节点（半成品），根据所有子项的最小齐套数设置
                demand.KitCount = demand.Children.Min(x => x.KitCount ?? 0);
                SetKitStatus(demand, needKitCount);
            }
        }

        /// <summary>
        /// 计算考虑领用配平的可分配套数
        /// </summary>
        /// <param name="demandItems">需求项列表</param>
        /// <param name="availableSupply">可用供应量</param>
        /// <param name="totalKitCount">订单总套数</param>
        /// <returns>可分配套数</returns>
        private int CalculateKitCountWithBalancing(
            List<DemandOrderDto> demandItems,
            decimal availableSupply,
            int totalKitCount
        )
        {
            if (demandItems == null || demandItems.Count == 0)
                return 0;

            //使用二分查找找到最大可分配套数
            int left = 0;
            int right = totalKitCount;
            int result = 0;

            while (left <= right)
            {
                int mid = (left + right) / 2;

                //检查是否能通过分配供应使所有明细达到mid套
                if (CanAchieveKitCount(demandItems, availableSupply, mid, totalKitCount))
                {
                    result = mid;
                    left = mid + 1; //尝试更大的套数
                }
                else
                {
                    right = mid - 1; //减少套数
                }
            }

            return result;
        }

        /// <summary>
        /// 检查是否能通过分配供应使所有明细达到指定套数
        /// </summary>
        /// <param name="demandItems">需求项列表</param>
        /// <param name="availableSupply">可用供应量</param>
        /// <param name="targetKitCount">目标套数</param>
        /// <param name="totalKitCount">订单总套数</param>
        /// <returns>是否可以达到</returns>
        private bool CanAchieveKitCount(
            List<DemandOrderDto> demandItems,
            decimal availableSupply,
            int targetKitCount,
            int totalKitCount
        )
        {
            if (targetKitCount == 0)
                return true;

            decimal totalSupplyNeeded = 0;

            foreach (var demandItem in demandItems)
            {
                //计算每套需要的数量（总需求量 / 总套数）
                decimal quantityPerKit = demandItem.AdjustedQuantity / totalKitCount;

                //计算达到目标套数需要的总量
                decimal targetQuantity = quantityPerKit * targetKitCount;

                //扣除已领用的部分，计算还需要从供应中分配的量
                decimal stillNeeded = Math.Max(0, targetQuantity - demandItem.IssuedQuantity);

                totalSupplyNeeded += stillNeeded;
            }

            //如果总需求 <= 可用供应，则可以达到目标套数
            return totalSupplyNeeded <= availableSupply;
        }

        /// <summary>
        /// 将树结构展平，收集所有最末级需求并按料号合并
        /// </summary>
        private void FlattenDemandTree(
            DemandOrderDto demand,
            int needKitCount,
            Dictionary<string, FlattenedDemandItemDto> flattenedDemands
        )
        {
            if (demand.Children == null || demand.Children.Count <= 0)
                return;

            foreach (var child in demand.Children)
            {
                //如果有子项，递归展开
                if (child.Children != null && child.Children.Count > 0)
                {
                    FlattenDemandTree(child, needKitCount, flattenedDemands);
                }
                else
                {
                    //叶子节点，按料号合并
                    if (!flattenedDemands.ContainsKey(child.ItemCode))
                    {
                        flattenedDemands[child.ItemCode] = new FlattenedDemandItemDto
                        {
                            ItemCode = child.ItemCode,
                            ItemName = child.ItemName,
                            ItemSpec = child.ItemSpec,
                            TotalDemandQuantity = 0,
                            TotalIssuedQuantity = 0,
                            DemandItems = new List<DemandOrderDto>(),
                        };
                    }

                    //累加总需求数量和总领用数量
                    flattenedDemands[child.ItemCode].TotalDemandQuantity += child.AdjustedQuantity;
                    flattenedDemands[child.ItemCode].TotalIssuedQuantity += child.IssuedQuantity;
                    flattenedDemands[child.ItemCode].DemandItems.Add(child);
                }
            }
        }
    }
}
